  // DlgAccelerator.cpp : implementation file
//

#include "stdafx.h"
#include "ansieditor.h"
#include "DlgAccelerator.h"

#include "FrameFuncs.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//typedef struct tagCommandInfo
//{
//	int		nCategory;
//	int		idCommand;
//	int		iBitmap;
//	BYTE	fVirt;
//	WORD	key;
//	//
//} CommandInfo;
/////////////////////////////////////////////////////////////////////////////
// CDlgAccelerator dialog

CDlgAccelerator::CDlgAccelerator(CWnd* pParent /*=NULL*/)
	: CDialog(CDlgAccelerator::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDlgAccelerator)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	m_bModified = FALSE;
	int nCount = gpPluginManager->GetPluginCount();
	mCommands = new CommandInfo[gnCommands + nCount];
	memcpy(mCommands, gCommands, sizeof(CommandInfo) * gnCommands);

	for(int n = 0; n < nCount; n++)
	{
		mCommands[gnCommands + n].nCategory = CATEGORY_PLUGIN;// gnMaxCommandCategory;
		mCommands[gnCommands + n].idCommand = IDM_PLUGIN_BASE + n;
		CPlugin *pPlugin = gpPluginManager->GetPluginByIndex(n);
		mCommands[gnCommands + n].iBitmap = pPlugin->m_iBitmap;
		mCommands[gnCommands + n].fVirt = pPlugin->m_fVirt;
		mCommands[gnCommands + n].key = pPlugin->m_key;
	}
	SplitString(gpApp->m_mui.LoadString(IDS_COMMAND_CATETORYS), '\n', m_arrCategory);

}

CDlgAccelerator::~CDlgAccelerator()
{
	delete [] mCommands;
	mCommands = 0;
}

void CDlgAccelerator::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDlgAccelerator)
	DDX_Control(pDX, IDC_HOTKEY1, m_hotkey);
	DDX_Control(pDX, IDC_LIST1, m_list);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CDlgAccelerator, CDialog)
	//{{AFX_MSG_MAP(CDlgAccelerator)
	ON_WM_SIZE()
	ON_NOTIFY(NM_CLICK, IDC_LIST1, OnClickList)
	ON_NOTIFY(NM_DBLCLK, IDC_LIST1, OnDblClkList)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDOK, OnOk)
	ON_BN_CLICKED(IDC_BTN_RESET, OnReset)
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnColumnClickList)
	//}}AFX_MSG_MAP
	ON_COMMAND(IDC_HOTKEY1, OnHotkey)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDlgAccelerator message handlers

BOOL CDlgAccelerator::OnInitDialog() 
{
	CDialog::OnInitDialog();

	m_list.ModifyStyle(0, LVS_SHAREIMAGELISTS|LVS_SHOWSELALWAYS|LVS_AUTOARRANGE|LVS_REPORT);
	m_list.SetExtendedStyle(LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT);//|LVS_EX_GRIDLINES);
	m_header.SubclassWindow(m_list.GetHeaderCtrl()->GetSafeHwnd());

	m_list.InsertColumn(0, gpApp->m_mui.LoadString(IDS_KBLISTCOL_0), LVCFMT_LEFT, 60);
	m_list.InsertColumn(1, gpApp->m_mui.LoadString(IDS_KBLISTCOL_1), LVCFMT_LEFT, 90);
	m_list.InsertColumn(2, gpApp->m_mui.LoadString(IDS_KBLISTCOL_2), LVCFMT_LEFT, 150);
	m_list.InsertColumn(3, gpApp->m_mui.LoadString(IDS_KBLISTCOL_3), LVCFMT_LEFT, 200);

	m_list.SetImageList(&(gpFrame->m_ilToolBar), LVSIL_SMALL);
//	m_list.SetBkColor(GetSysColor(COLOR_BTNFACE));
//	m_list.SetTextBkColor(GetSysColor(COLOR_BTNFACE));
	
	FillList();

//	GetDlgItem(IDOK)->EnableWindow(FALSE);
	ModifyStyleEx(0, WS_EX_DLGMODALFRAME);

	m_hotkey.ModifyStyleEx(WS_EX_CLIENTEDGE, 0);
	m_hotkey.ModifyStyle(0, WS_BORDER);
	m_hotkey.ShowWindow(SW_HIDE);
//	m_hotkey.SetFont(m_list.GetFont());
	
	WINDOWPLACEMENT *pwp;
	UINT nSize = sizeof(WINDOWPLACEMENT);
	AfxGetApp()->GetProfileBinary("DlgAccelerator" ,"State", (LPBYTE*)&pwp, &nSize);
	if(pwp)
	{
		SetWindowPlacement(pwp);
		delete *(LPBYTE*)&pwp;
	}

	CenterWindow();

	m_font.CreatePointFont(90, "Tahoma");
	m_list.SetFont(&m_font);
	m_hotkey.SetFont(&m_font);

	m_list.m_wndInPlaceCtrl = &m_hotkey;
	
	gpApp->m_mui.UpdateDialog(this, IDD);
	return TRUE;
}

void CDlgAccelerator::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);

	m_list.MoveWindow(14, 14, cx - 28, cy - 53);
	GetDlgItem(IDCANCEL)->MoveWindow(cx - 84, cy - 31, 70, 23);
	GetDlgItem(IDC_BTN_RESET)->MoveWindow(cx - 240, cy - 31, 70, 23);
	GetDlgItem(IDOK)->MoveWindow(cx - 162, cy - 31, 70, 23);
	GetDlgItem(IDOK)->Invalidate();
}

void CDlgAccelerator::FillList()
{
	m_list.DeleteAllItems();

	int nCommands = gnCommands + gpPluginManager->GetPluginCount();

	int nItem = 0;
	for(int n = 0; n < nCommands; ++n)
	{
		CString sCategory, sDesc, sName;
		if(!GetCommandText(n, &sCategory, &sDesc, &sName))
		{
			continue;
		}

		nItem = m_list.InsertItem(nItem, sCategory, mCommands[n].iBitmap);
		m_list.SetItemText(nItem, 1, sName);

		m_list.SetItemText(nItem, 2, HotKeyToString(mCommands[n].fVirt, mCommands[n].key));
		m_list.SetItemText(nItem, 3, sDesc);

		m_list.SetItemData(nItem, n);
	}


//	int naCols[] = { 1, 0, 2, 3 };
//	m_list.SetColumnOrderArray(4, naCols);
}

void CDlgAccelerator::OnClickList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;
}

BYTE CDlgAccelerator::HotKeyToAccel(WORD wModifiers)
{
	BYTE bt = FVIRTKEY;
	if(wModifiers & HOTKEYF_CONTROL)
	{
		bt |= FCONTROL;
	}
	if(wModifiers & HOTKEYF_SHIFT)
	{
		bt |= FSHIFT;
	}
	if(wModifiers & HOTKEYF_ALT)
	{
		bt |= FALT;
	}
	return bt;
}

WORD CDlgAccelerator::AccelToHotKey(BYTE fVirst)
{
	WORD wModifyers = 0;
	if(fVirst & FCONTROL)
	{
		wModifyers |= HOTKEYF_CONTROL;
	}
	if(fVirst & FSHIFT)
	{
		wModifyers |= HOTKEYF_SHIFT;
	}
	if(fVirst & FALT)
	{
		wModifyers |= HOTKEYF_ALT;
	}
	return wModifyers;
}

void CDlgAccelerator::OnHotkey()
{
	int nItem = m_hotkey.nItem;
	int nIndex = m_list.GetItemData(nItem);

	WORD key = 0, wModifiers = 0;
	m_hotkey.GetHotKey(key, wModifiers);

	//check duplicate
	int nCommandCount = gnCommands + gpPluginManager->GetPluginCount(); 
	BYTE fVirt = HotKeyToAccel(wModifiers);
	BOOL bDuplicate = FALSE;
	int n;
	for(n = 0; n < nCommandCount; n++)
	{
		if((mCommands[n].fVirt == fVirt) && (mCommands[n].key == key) && (n != nIndex))
		{
			bDuplicate = TRUE;
			break;
		}
	}
	if(bDuplicate)
	{
		CString sCategory, sName;
		GetCommandText(n, &sCategory, &sName);

		CString sInfo;
		sInfo.Format(gpApp->m_mui.LoadString(IDS_DUPLICATE_SHORTCUT_PROMPT), sCategory, sName);
		if(MessageBox(sInfo, gpApp->m_mui.LoadString(IDS_HINT), MB_YESNO|MB_ICONQUESTION) == IDNO)
		{
			return;
		}
	}

	mCommands[nIndex].fVirt = HotKeyToAccel(wModifiers);
	mCommands[nIndex].key = key;
	m_list.SetItemText(nItem, 2, HotKeyToString(mCommands[nIndex].fVirt, key));
	m_bModified = TRUE;
}

void CDlgAccelerator::OnDblClkList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	LPNMITEMACTIVATE pnmia = (LPNMITEMACTIVATE)pNMHDR;
	CRect rect;

	int nItem = pnmia->iItem;
	int nSubItem = 2;
	if(nItem == -1)
	{
		return;
	}
	CString sText = m_list.GetItemText(nItem, nSubItem);
	m_list.GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);

	CRect rcList;
	m_list.GetClientRect(rcList);
	m_list.ClientToScreen(rcList);

	CRect rcDlg;
	GetClientRect(rcDlg);
	ClientToScreen(rcDlg);

	int nIndex = m_list.GetItemData(pnmia->iItem);
	m_hotkey.SetWindowPos(&m_list, rect.left + rcList.left - rcDlg.left, rect.top + rcList.top - rcDlg.top, 
						  rect.Width(), rect.Height(), SWP_SHOWWINDOW|SWP_DRAWFRAME);
	m_hotkey.SetHotKey(mCommands[nIndex].key, AccelToHotKey(mCommands[nIndex].fVirt));
	m_hotkey.nItem = nItem;
	m_hotkey.SetFocus();

	*pResult = 0;
}

BOOL CDlgAccelerator::PreTranslateMessage(MSG* pMsg) 
{
	if((pMsg->message == WM_KEYDOWN))
	{
		if(pMsg->wParam == VK_ESCAPE)
		{
			if(GetFocus() == &m_hotkey)
			{
				m_hotkey.Reset();
				m_list.SetFocus();
				return TRUE;
			}
		}
		else if(pMsg->wParam == VK_RETURN)
		{
			if(GetFocus() == &m_list)
			{
				static NMITEMACTIVATE nmia;
				nmia.hdr.idFrom = IDC_LIST1;
				nmia.hdr.code = NM_DBLCLK;
				nmia.hdr.hwndFrom = m_list.GetSafeHwnd();
				nmia.iItem = m_list.GetSelectionMark();
				nmia.iSubItem = 2;
				SendMessage(WM_NOTIFY, NM_DBLCLK, (LPARAM)(LPNMHDR)&nmia);
			}
			else
			{
				m_list.SetFocus();
			}
			return TRUE;
		}
	}
	else if(pMsg->message == WM_KEYUP && pMsg->wParam == VK_RETURN)
	{
		return TRUE;
	}
	else if(pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_RBUTTONDOWN)
	{
		m_list.SetFocus();
	}
	return CDialog::PreTranslateMessage(pMsg);
}

void CDlgAccelerator::OnDestroy() 
{
	WINDOWPLACEMENT wp;
	wp.length = sizeof(wp);
	GetWindowPlacement(&wp);
	AfxGetApp()->WriteProfileBinary("DlgAccelerator", "State", (LPBYTE)&wp, wp.length);

	CDialog::OnDestroy();
}

void CDlgAccelerator::OnCancel() 
{
	CDialog::OnCancel();
}

void CDlgAccelerator::OnOk() 
{
	if(m_bModified)
	{
		memcpy(gCommands, mCommands, sizeof(CommandInfo) * gnCommands);
		int nCount = gpPluginManager->GetPluginCount();
		for(int n = 0; n < nCount; n++)
		{
			CPlugin *pPlugin = gpPluginManager->GetPluginByIndex(n);
			pPlugin->m_fVirt = mCommands[gnCommands + n].fVirt;
			pPlugin->m_key = mCommands[gnCommands + n].key;
		}
		CFrameFuncs::LoadAccelerators(&gpFrame->m_hAccelTable);
		//gpFrame->LoadAccelerators();
		
	}
	CDialog::OnOK();
}

void CDlgAccelerator::OnReset() 
{
	CommandInfo *pCommands;
	UINT nSize = sizeof(CommandInfo) * gnCommands;
	gpApp->GetProfileBinary(gszProfileName, "DefaultAccelerators", (LPBYTE*)&pCommands, &nSize);
	if(pCommands)
	{
		memcpy(mCommands, pCommands, nSize);
		delete *(LPBYTE*)&pCommands;
	}
	int nCount = gpPluginManager->GetPluginCount();
	for(int n = 0; n < nCount; n++)
	{
		mCommands[gnCommands + n].fVirt = 0;
		mCommands[gnCommands + n].key = 0;
	}

	FillList();
	m_bModified = TRUE;
}

void CDlgAccelerator::OnColumnClickList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	CWaitCursor cw;
	NMLISTVIEW *pnmlv = (NMLISTVIEW*)pNMHDR;

	int nSortCol = pnmlv->iSubItem;
	BOOL bSortAsc = m_header.GetSortAsc();
	if(nSortCol == m_header.GetSortCol())
	{
		bSortAsc = !bSortAsc;
	}

	m_header.SetSortStatus(nSortCol, bSortAsc);

	SortInfo si;
	si.pheader = &m_header;
	si.plist = &m_list;
	ListView_SortItemsEx(m_list.GetSafeHwnd(), compare, (LPARAM)&si);
	
	*pResult = 0;
}

int CALLBACK CDlgAccelerator::compare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	SortInfo *psi = (SortInfo*)lParamSort;
	int nSortCol = psi->pheader->GetSortCol();
	BOOL bSortAsc = psi->pheader->GetSortAsc();
	CString s1 = psi->plist->GetItemText(lParam1, nSortCol);
	CString s2 = psi->plist->GetItemText(lParam2, nSortCol);

	int nResult = s1.CompareNoCase(s2);
	if(!bSortAsc)
	{
		nResult *= -1;
	}
	return nResult;
}

BOOL CDlgAccelerator::GetCommandText(int nIndex, CString* psCategory, CString* psName, CString* psDesc)
{
	if(psCategory) *psCategory = m_arrCategory[mCommands[nIndex].nCategory];
	if(nIndex < gnCommands)
	{
		CString sCommand = gpApp->m_mui.LoadString(mCommands[nIndex].idCommand);
		int nPos = sCommand.Find('\n');
		if(psName) *psName = sCommand.Left(nPos);
		if(psDesc) *psDesc = sCommand.Mid(nPos + 1);
	}
	else
	{
		if(psName) *psName = gpPluginManager->GetPluginByIndex(nIndex - gnCommands)->GetMenuName();
		if(psDesc) *psDesc = gpPluginManager->GetPluginByIndex(nIndex - gnCommands)->GetMenuDescription();
	}
	return TRUE;
}